#include <sys/types.h>
#include <getopt.h>
#include <pthread.h>
#include "command.h"
#include "common/rfc.h"
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "common/util.h"
#include "gui/gui_interface.h"
#include "client/client.h"
#include "client/listener.h"
#include <string.h>

#define MAX_NAME_LENGTH (32)

/*
 *      interne Prototypen
 */
static int parseCommandline(int argc, char **argv);
void PrintHelp();
int main(int argc, char **argv);
void Login(char* name);
extern void HandleError(struct NET_MESSAGE* msg);


/*
 *      Modulobale Variablen
 */
struct ST_GLOBAL_CLIENT_INFO clientInfo;
pthread_t listener_thread_id;
char* port = TCP_DEFAULT_PORT;
char* serverIP = TCP_DEFAULT_HOST;

/*
 *      Implementierungen der Funktionen
 */
static int parseCommandline(int argc, char **argv)
{
        while (optind < argc)
        {
                int result = getopt(argc, argv, "-p:dh:n:");

                if (result == -1)
                        return 0; /* end of list */
                switch (result)
                {
                case '?':
                        fprintf(stderr, "Unbekannter Parameter");
                        PrintHelp();
                        exit(0);

                case ':': /* parameter fehlt*/
                        fprintf(stderr, "Fehlendes Argument");
                        PrintHelp();
                        exit(0);

                case 'n':
                        clientInfo.name = (char*) optarg;
                        break;

                case 'p':
                        port = (char*) optarg;
                        infoPrint("Manueller Port: = %s", port);
                        break;

                case 'h':
                        serverIP = (char*) optarg;
                        infoPrint("Manueller Host: %s", serverIP);
                        break;

                case 'd':
                        debugEnable();
                        infoPrint("Debugmodus an");
                        break;

                default:
                        fprintf(stderr, "Fehler Argumentauswertung.\n");
                        PrintHelp();
                        exit(0);
                }
        }
        return 0;
}

int main(int argc, char **argv)
{
        int thread;

        // hole Kommandozeilenparamter
        parseCommandline(argc, argv);

        // prüfe Name
        if (clientInfo.name == NULL)
        {
                printf("Keine Name angegeben! Beende Client!\n");
                PrintHelp();
                return 0;
        }
        else if (strlen(clientInfo.name) > MAX_NAME_LENGTH - 1)
        {
                printf("Name ist zu lang! Beende Client!\n");
                return 0;
        }

        setProgName(argv[0]);
        printf("%s ", clientInfo.name);
        infoPrint("Starte Client der Gruppe Buchmaier/Wolf/Heissenberger");

        // erstelle client socket
        clientInfo.sock = CreateClientSocket(serverIP, port);
        infoPrint("Client Socket");
        printf("%s ", clientInfo.name);
        // wenn Verbindungsaufbau erfolgreich
        if (clientInfo.sock <= 0)
        {
                infoPrint("Konnte keine Verbindung zum Server herstellen! Beende Client...");
        }
        else
        {
                // debug Ausgaben
        	printf("Log");
                debugPrint("Loging in...");
                debugPrint("initializing GUI");

                // initialisiere GUI
                guiInit(&argc, &argv);
                preparation_showWindow();

                // logge auf dem Server ein
                Login(clientInfo.name);

                // starte Listener Thread zum empfangen von Nachrichten
                thread = pthread_create(&listener_thread_id, NULL, &listener_thread, (void*) &clientInfo);
                if (thread)
                {
                        printf("Konnte Listener-Thread nicht starten\n");
                        exit(0);
                }

                // passives Warten des Threads
                guiMain();

                // GUI freigeben
                guiDestroy();
                guiQuit();
        }

        return 0;
}

void PrintHelp()
{
        printf("Aufruf:  ./client -n NAME\n");
        printf("[-d] [-p PORTNUMMER] [-h SERVERIP]\n");
        printf("Standard für PORT ist: 54321\nStandard für Host IP ist 127.0.0.1\n");
        exit(0);
}

void Login(char* name)
{

        struct NET_MESSAGE senddata;

        // sende Login
        senddata = PackRFCMsg(TYPE_IS_LOGIN_REQUEST, strlen(name), name);
        if (SendRFCMsg(clientInfo.sock, &senddata) > 0)
                debugPrint("Login gesendet");
        else
        {
                debugPrint("Konnte Login nicht senden!");
                guiShowErrorDialog("Konnte Login nicht senden!", 1);
        }

        // empfange LoginResponse
        struct NET_MESSAGE recvdata;

        // Fehler beim empfangen
        if (ReceiveRFCMsg(clientInfo.sock, &recvdata) < 0)
        {
                debugPrint("Fehler beim Empfangen des LoginResponse");
                guiShowErrorDialog("Konnte Login nicht senden!", 1);
        }
        // RFC Nachricht empfangen
        else
        {
                // switche auf Headertypen
                switch (recvdata.header.type)
                {
                case TYPE_IS_LOGIN_RESPONSE_OK:

                        memmove(&clientInfo.ID, recvdata.data, recvdata.header.size);
                        break;

                case TYPE_IS_ERROR:

                        HandleError(&recvdata);
                        break;
                }
        }

        // Speicher freigeben
        SecureFree(recvdata.data);
        recvdata.data = NULL;

        // Wenn Client-ID = 0 wird Client Spielleiter
        if (clientInfo.ID == 0)
        {
                // Schalte Spielleiter-Rechte frei
                preparation_setMode(PREPARATION_MODE_PRIVILEGED);
                debugPrint("Login erfolgreich! Client ist Spielleiter");
        }
        else
        {
                // Client ist normaler Spieler
                preparation_setMode(PREPARATION_MODE_NORMAL);
                debugPrint("Login erfolgreich! Client ID: %d", clientInfo.ID);
        }
}


